import javafx.scene.paint.Color;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class Board {
    private Color[][] board;
    private int width;
    private int height;
    private Piece currentPiece;
    private Piece nextPiece;
    private Random random;
    private int score = 0;
    private int level = 1;
    private int linesCleared = 0;
    private int initialSpeed = 5;
    private List<ScoreListener> scoreListeners = new ArrayList<>();
    private List<LevelListener> levelListeners = new ArrayList<>();
    private List<LinesListener> linesListeners = new ArrayList<>();
    private List<NextPieceListener> nextPieceListeners = new ArrayList<>();
    private List<GameOverListener> gameOverListeners = new ArrayList<>();
    
    public Board(int width, int height) {
        this.width = width;
        this.height = height;
        this.board = new Color[height][width];
        this.random = new Random();
        initializeBoard();
    }
    
    public void setInitialSpeed(int speed) {
        this.initialSpeed = speed;
    }
    
    public void setScoreListener(ScoreListener listener) {
        scoreListeners.add(listener);
    }
    
    public void setLevelListener(LevelListener listener) {
        levelListeners.add(listener);
    }
    
    public void setLinesListener(LinesListener listener) {
        linesListeners.add(listener);
    }
    
    public void setNextPieceListener(NextPieceListener listener) {
        nextPieceListeners.add(listener);
    }
    
    public void setGameOverListener(GameOverListener listener) {
        gameOverListeners.add(listener);
    }
    
    private void initializeBoard() {
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                board[y][x] = null;
            }
        }
    }
    
    public void reset() {
        initializeBoard();
        score = 0;
        level = 1;
        linesCleared = 0;
        notifyScoreChanged(score);
        notifyLevelChanged(level);
        notifyLinesChanged(linesCleared);
        
        nextPiece = createRandomPiece();
        spawnNewPiece();
    }
    
    private Piece createRandomPiece() {
        PieceType[] types = PieceType.values();
        PieceType randomType = types[random.nextInt(types.length)];
        return new Piece(randomType);
    }
    
    public void spawnNewPiece() {
        currentPiece = nextPiece;
        nextPiece = createRandomPiece();
        
        // 放置新方块在顶部中央
        currentPiece.setX(width / 2 - currentPiece.getShape()[0].length / 2);
        currentPiece.setY(0);
        
        // 通知下一个方块变化
        notifyNextPieceChanged(nextPiece);
        
        // 检查游戏是否结束
        if (checkCollision()) {
            notifyGameOver();
        }
    }
    
    public boolean movePieceLeft() {
        currentPiece.setX(currentPiece.getX() - 1);
        if (checkCollision()) {
            currentPiece.setX(currentPiece.getX() + 1);
            return false;
        }
        return true;
    }
    
    public boolean movePieceRight() {
        currentPiece.setX(currentPiece.getX() + 1);
        if (checkCollision()) {
            currentPiece.setX(currentPiece.getX() - 1);
            return false;
        }
        return true;
    }
    
    public boolean movePieceDown() {
        currentPiece.setY(currentPiece.getY() + 1);
        if (checkCollision()) {
            currentPiece.setY(currentPiece.getY() - 1);
            lockPiece();
            clearLines();
            spawnNewPiece();
            return false;
        }
        return true;
    }
    
    public void hardDrop() {
        int dropDistance = 0;
        while (movePieceDown()) {
            dropDistance++;
        }
        // 硬降得分：每下落一格得2分
        addScore(dropDistance * 2);
    }
    
    public boolean rotatePieceClockwise() {
        currentPiece.rotateClockwise();
        if (checkCollision()) {
            // 尝试墙踢
            if (!wallKick()) {
                currentPiece.rotateCounterClockwise();
                return false;
            }
        }
        return true;
    }
    
    public boolean rotatePieceCounterClockwise() {
        currentPiece.rotateCounterClockwise();
        if (checkCollision()) {
            // 尝试墙踢
            if (!wallKick()) {
                currentPiece.rotateClockwise();
                return false;
            }
        }
        return true;
    }
    
    private boolean wallKick() {
        // 简单的墙踢实现：尝试向左或向右移动一格
        if (movePieceLeft()) {
            return true;
        }
        
        if (movePieceRight()) {
            return true;
        }
        
        return false;
    }
    
    private boolean checkCollision() {
        int[][] shape = currentPiece.getShape();
        int x = currentPiece.getX();
        int y = currentPiece.getY();
        
        for (int i = 0; i < shape.length; i++) {
            for (int j = 0; j < shape[i].length; j++) {
                if (shape[i][j] != 0) {
                    int boardX = x + j;
                    int boardY = y + i;
                    
                    // 检查边界
                    if (boardX < 0 || boardX >= width || boardY >= height) {
                        return true;
                    }
                    
                    // 检查是否与已有方块重叠
                    if (boardY >= 0 && board[boardY][boardX] != null) {
                        return true;
                    }
                }
            }
        }
        
        return false;
    }
    
    private void lockPiece() {
        int[][] shape = currentPiece.getShape();
        int x = currentPiece.getX();
        int y = currentPiece.getY();
        Color color = currentPiece.getColor();
        
        for (int i = 0; i < shape.length; i++) {
            for (int j = 0; j < shape[i].length; j++) {
                if (shape[i][j] != 0) {
                    int boardX = x + j;
                    int boardY = y + i;
                    
                    if (boardY >= 0) { // 确保不超出上边界
                        board[boardY][boardX] = color;
                    }
                }
            }
        }
    }
    
    private void clearLines() {
        List<Integer> linesToClear = new ArrayList<>();
        
        for (int y = height - 1; y >= 0; y--) {
            boolean lineFull = true;
            for (int x = 0; x < width; x++) {
                if (board[y][x] == null) {
                    lineFull = false;
                    break;
                }
            }
            
            if (lineFull) {
                linesToClear.add(y);
            }
        }
        
        if (!linesToClear.isEmpty()) {
            // 清除行并移动上方方块
            for (int line : linesToClear) {
                for (int y = line; y > 0; y--) {
                    board[y] = Arrays.copyOf(board[y - 1], width);
                }
                board[0] = new Color[width]; // 顶部添加新行
            }
            
            // 更新分数和等级
            int lines = linesToClear.size();
            addLines(lines);
            
            // 根据消除的行数计算分数
            int lineScore = 0;
            switch (lines) {
                case 1:
                    lineScore = 100 * level;
                    break;
                case 2:
                    lineScore = 300 * level;
                    break;
                case 3:
                    lineScore = 500 * level;
                    break;
                case 4:
                    lineScore = 800 * level;
                    break;
            }
            addScore(lineScore);
        }
    }
    
    private void addScore(int points) {
        score += points;
        notifyScoreChanged(score);
    }
    
    private void addLines(int lines) {
        linesCleared += lines;
        notifyLinesChanged(linesCleared);
        
        // 每消除10行提升一个等级
        int newLevel = (linesCleared / 10) + 1;
        if (newLevel > level) {
            level = newLevel;
            notifyLevelChanged(level);
        }
    }
    
    public double getDropInterval() {
        // 根据等级调整下落间隔，等级越高，下落越快
        return Math.max(0.1, 1.0 - (level - 1) * 0.1);
    }
    
    public Color[][] getBoardState() {
        return board;
    }
    
    public Piece getCurrentPiece() {
        return currentPiece;
    }
    
    public Piece getNextPiece() {
        return nextPiece;
    }
    
    public int getScore() {
        return score;
    }
    
    private void notifyScoreChanged(int score) {
        for (ScoreListener listener : scoreListeners) {
            listener.onScoreChanged(score);
        }
    }
    
    private void notifyLevelChanged(int level) {
        for (LevelListener listener : levelListeners) {
            listener.onLevelChanged(level);
        }
    }
    
    private void notifyLinesChanged(int lines) {
        for (LinesListener listener : linesListeners) {
            listener.onLinesChanged(lines);
        }
    }
    
    private void notifyNextPieceChanged(Piece nextPiece) {
        for (NextPieceListener listener : nextPieceListeners) {
            listener.onNextPieceChanged(nextPiece);
        }
    }
    
    private void notifyGameOver() {
        for (GameOverListener listener : gameOverListeners) {
            listener.onGameOver();
        }
    }
    
    // 监听器接口
    public interface ScoreListener {
        void onScoreChanged(int score);
    }
    
    public interface LevelListener {
        void onLevelChanged(int level);
    }
    
    public interface LinesListener {
        void onLinesChanged(int lines);
    }
    
    public interface NextPieceListener {
        void onNextPieceChanged(Piece nextPiece);
    }
    
    public interface GameOverListener {
        void onGameOver();
    }
}
